const isObj = obj => Object.prototype.toString.call(obj) === '[object Object]';

class Observer {
  constructor(option) {
    this.count = 0;
    this.handle = [];
    this.init(option);
  }

  init(option) {
    this.appName = option.appName;
    this.api = option.api || 'callNativeBridgeApi';
    this.androidApi = option.androidApi || 'dx';
    this.iosApi = option.iosApi || '';
    if (Object.prototype.hasOwnProperty.call(window, this.androidApi)) {
      this.nativeEnv = 'android';
    } else if (Object.prototype.hasOwnProperty.call(window, this.iosApi || this.api)) {
      this.nativeEnv = 'ios';
    } else {
      this.nativeEnv = '';
    }
  }

  // add subscribe
  add(topic, params, fn) {
    const { nativeEnv } = this;
    const id = `${this.count += 1}_${Math.floor(Math.random() * 100)}_${new Date().getTime()}`;
    const cb = typeof params === 'function' ? params : fn;
    if (nativeEnv) {
      const { api, androidApi, iosApi } = this;
      const data = { bridgeName: topic, data: isObj(params) ? params : {}, callbackId: id };
      if (nativeEnv === 'android') {
        window[androidApi][api](JSON.stringify(data));
      } else if (iosApi) {
        window[iosApi][api](data);
      } else {
        window[api](data);
      }
    } else if (cb) {
      return cb({
        success: false,
        msg: '环境出错',
        code: -2,
        data: {}
      });
    }
    const subscribe = { topic, id, fn: cb };
    this.handle.push(subscribe);
    return subscribe;
  }

  // remove subscribe
  remove(id) {
    let index;
    this.handle.forEach(({ callbackId }, i) => {
      if (callbackId === id) index = i;
    });
    delete this.handle[index];
  }

  // publish subscribe
  publish(result) {
    const { callbackId } = result;
    this.handle.forEach(({ id, fn }) => {
      if (id === callbackId && typeof fn === 'function') fn(result);
    });
  }
}

export default Observer;
